﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using  Windows.UI.Xaml;
using Windows.UI.Xaml.Data;

namespace G.Controls
{  
    /// <summary>
    /// 使用本类可以方便的将DependencyObject属性的变化通过事件的方式反馈给使用者
    /// </summary>
    public class PropertyChangedNotify : FrameworkElement, IValueConverter//关键是通过converter截取属性的变化通知
    {
        #region ListenerProperty
        /// <summary>
        /// 注册或者注销PropertyChangedNotify
        /// </summary>
        public static readonly DependencyProperty ListenerProperty = DependencyProperty.RegisterAttached("Listener", typeof(PropertyChangedNotify), typeof(PropertyChangedNotify), new PropertyMetadata(null, OnListenerChanged));

        private static void OnListenerChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            var newValue = e.NewValue as PropertyChangedNotify;
            if (newValue != null)
                newValue.Initial(o);
            else
            {
                var oldValue = e.OldValue as PropertyChangedNotify;
                if (oldValue != null)
                {
                    oldValue.RemoveBinding();
                }
            }
        }

        public static PropertyChangedNotify GetListener(DependencyObject element)
        {  
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }

            return element.GetValue(ListenerProperty) as PropertyChangedNotify;
        }


        public static void SetListener(DependencyObject element, PropertyChangedNotify value)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }
            element.SetValue(ListenerProperty, value);
        }

        #endregion

        public static readonly DependencyProperty PathProperty = DependencyProperty.Register("Path", typeof(PropertyPath), typeof(PropertyChangedNotify), null);
        //[TypeConverter(typeof(PropertyPathConverter))]
        public PropertyPath Path
        {
            get
            {
                return (PropertyPath)this.GetValue(PathProperty);
            }
            set
            {
                this.SetValue(PathProperty, value);
            }
        }
        private DependencyObject target;
        private void Initial(DependencyObject target)
        {
            this.target = target;
            Binding bingding = new Binding
            {
                Path = this.Path,
                Converter = this,
                Source = this.target
            };
            this.SetBinding(TagProperty, bingding);
        }
        private void RemoveBinding()
        {
            this.SetBinding(TagProperty, null);
        }
        public event PropertyValueChangedHandle PropertyValueChanged;
        object oldValue;
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            if (PropertyValueChanged != null)
            {
                this.PropertyValueChanged(this.target, new PropertyValueChangedEventArgs(oldValue, value));
                this.oldValue = value;
            }
            return value;
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }

    public delegate void PropertyValueChangedHandle(DependencyObject d, PropertyValueChangedEventArgs e);

    public class PropertyValueChangedEventArgs : EventArgs
    {
        public object OldValue { get; private set; }
        public object NewValue { get; private set; }
        internal PropertyValueChangedEventArgs(object oldValue, object newValue)
        {
            this.OldValue = oldValue;
            this.NewValue = newValue;
        }
    }
}
